package controller;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import java.util.logging.Level;
import java.util.logging.Logger;
import model.MoodleException;
import model.MoodleUser;
import model.UserCustomField;
import model.UserPreference;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
import service.MoodleRestWSConfigSingleton;
import service.MoodleRestWSConnector;

/**
 * User controller with Moodle user function implementation.
 *
 * @author Sergey Nikonenko
 */
public class MoodleUserWS {

    private final JSONParser parser = new JSONParser();

    /**
     * Universal method creating users.
     *
     * @param newUsers set of users that will be created
     * @return set of created user identified by their id and name
     * @throws model.MoodleException
     * @throws org.json.simple.parser.ParseException
     */
    public Set<MoodleUser> createUsers(Set<MoodleUser> newUsers) throws MoodleException, ParseException {
        MoodleRestWSConfigSingleton config = MoodleRestWSConfigSingleton.getInstance();

        String domainName = config.getDomainName();
        String token = config.getToken();
        String restformat = config.getRestFormat();
        
        //Web-service's function name
        String functionName = "core_user_create_users";
         StringBuilder urlParameters = new StringBuilder();
        int i = 0;
        
         for (MoodleUser user : newUsers) {
            try {
                urlParameters.append("&users[").append(i).append("][username]=").append(URLEncoder.encode(user.getUsername(), "UTF-8"))
                        .append("&users[").append(i).append("][password]=").append(URLEncoder.encode(user.getPassword(), "UTF-8"))
                        .append("&users[").append(i).append("][firstname]=").append(URLEncoder.encode(user.getFirstname(), "UTF-8"))
                        .append("&users[").append(i).append("][lastname]=").append(URLEncoder.encode(user.getLastname(), "UTF-8"))
                        .append("&users[").append(i).append("][email]=").append(URLEncoder.encode(user.getEmail(), "UTF-8"))
                        .append("&users[").append(i).append("][auth]=").append(URLEncoder.encode(user.getAuth(), "UTF-8"))
                        .append("&users[").append(i).append("][idnumber]=").append(URLEncoder.encode(user.getIdnumber(), "UTF-8"))
                        .append("&users[").append(i).append("][lang]=").append(URLEncoder.encode(user.getLang(), "UTF-8"))
                        .append("&users[").append(i).append("][calendartype]=").append(URLEncoder.encode(user.getCalendartype(), "UTF-8"))
                        .append("&users[").append(i).append("][theme]=").append(URLEncoder.encode(user.getTheme(), "UTF-8"))
                        .append("&users[").append(i).append("][timezone]=").append(URLEncoder.encode(user.getTimezone(), "UTF-8"))
                        .append("&users[").append(i).append("][mailformat]=").append(user.getMailformat())
                        .append("&users[").append(i).append("][description]=").append(URLEncoder.encode(user.getDescription(), "UTF-8"))
                        .append("&users[").append(i).append("][city]=").append(URLEncoder.encode(user.getCity(), "UTF-8"))
                        .append("&users[").append(i).append("][country]=").append(URLEncoder.encode(user.getCountry(), "UTF-8"))
                        .append("&users[").append(i).append("][firstnamephonetic]=").append(URLEncoder.encode(user.getFirstnamephonetic(), "UTF-8"))
                        .append("&users[").append(i).append("][lastnamephonetic]=").append(URLEncoder.encode(user.getLastnamephonetic(), "UTF-8"));
                         int j = 0;
                for (UserCustomField customField: user.getCustomfields()) {
                    urlParameters.append("&users[").append(i).append("][usercustomfield][").append(j).append("][name]=").append(URLEncoder.encode(customField.getName(), "UTF-8"))
                            .append("&users[").append(i).append("][usercustomfield][").append(j).append("][value]=").append(URLEncoder.encode(customField.getValue(), "UTF-8"))
                            .append("&users[").append(i).append("][usercustomfield][").append(j).append("][type]=").append(URLEncoder.encode(customField.getType(), "UTF-8"))
                            .append("&users[").append(i).append("][usercustomfield][").append(j).append("][shortname]=").append(URLEncoder.encode(customField.getShortname(), "UTF-8"))
                            ;
                    j++;
                }
                             int k = 0;
                for (UserPreference userPreference: user.getUserpreferences()) {
                    urlParameters.append("&users[").append(i).append("][userpreference][").append(j).append("][name]=").append(URLEncoder.encode(userPreference.getName(), "UTF-8"))
                                 .append("&users[").append(i).append("][userpreference][").append(j).append("][value]=").append(URLEncoder.encode(userPreference.getValue(), "UTF-8"));                 
                    k++;
                }
            } catch (UnsupportedEncodingException ex) {
                Logger.getLogger(MoodleUserWS.class
                        .getName()).log(Level.SEVERE, null, ex);
            }
            i++;
        }
          //Request to Web-service's function invoke
        String response = MoodleRestWSConnector.moodleWSRestCall(restformat, domainName, token, functionName, urlParameters.toString());
        
        Set<MoodleUser> users = new HashSet<MoodleUser>();
        //Parsing of JSON-response
        Object obj = parser.parse(response);
        JSONArray array = (JSONArray) obj;
        //Fore some id it was empty array
        if (array.size() != 0) {
            for (Object arrayItem : array) {
                JSONObject jsonObj = (JSONObject) arrayItem;
                long id = (long) jsonObj.get("id");
                String username = jsonObj.get("username").toString();
                MoodleUser user = new MoodleUser(id, username);
                users.add(user);
            }
        }

        return users;
    }
    /**
     * Creates a single user(supplementary method).
     *
     * @param newUser  category to be created
     * @return created {@code MoodleUser} instance
     * @throws model.MoodleException if {@code createUsers} method throws {@code MoodleException}
     * @throws org.json.simple.parser.ParseException if {@code createUsers} method throws {@code ParseException}
     */
     public MoodleUser createUser(MoodleUser newUser) throws MoodleException, ParseException {
        Set<MoodleUser> newUsers = new HashSet<MoodleUser>();
        newUsers.add(newUser);
        Set<MoodleUser> createdUsers = createUsers(newUsers);
        MoodleUser createdUser = createdUsers.iterator().next();
        return createdUser;
    }
    
    /**
     * Universal method for getting of users.
     * @param criteria  the key/value pairs to be considered in user search. 
     * Values can not be empty. Specify different keys only once (fullname => 'user1', auth => 'manual', ...) - key occurences are forbidden. 
     * The search is executed with AND operator on the criterias. Invalid criterias (keys) are ignored, the search is still executed on the valid criterias. 
     * You can search without criteria, but the function is not designed for it. It could very slow or timeout. The function is designed to search some specific users.
     * @throws MoodleException
     * @throws ParseException
     */
    public Set<MoodleUser> getUsers(Map<String, String> criteria) throws MoodleException, ParseException {

        MoodleRestWSConfigSingleton config = MoodleRestWSConfigSingleton.getInstance();

        String domainName = config.getDomainName();
        String token = config.getToken();
        String restformat = config.getRestFormat();
        //Web-service's function name
        String functionName = "core_user_get_users";
        StringBuilder urlParameters = new StringBuilder();
        //Empty criteria makes return the full list of categories
        if (criteria.isEmpty()) {
            urlParameters.append("");
        } else {
            int i = 0;
            for (String key : criteria.keySet()) {
                urlParameters.append("&criteria[").append(i).append("][key]=").append(key)
                        .append("&criteria[").append(i).append("][value]=").append(criteria.get(key));
                i++;
            }
           
        }
         //Request to Web-service's function invoke
        String response = MoodleRestWSConnector.moodleWSRestCall(restformat, domainName, token, functionName, urlParameters.toString());
        /*Use TreeSet for getting users in sorted order*/
        Set<MoodleUser> users = new HashSet<MoodleUser>();        
        //Parsing of JSON-response
        Object obj = parser.parse(response);
        JSONObject jsonObj = (JSONObject) obj;
        JSONArray jsonUsers = (JSONArray) jsonObj.get("users");
        //Fore some id it was empty array
        if (jsonUsers.size() != 0) {
            for (Object arrayItem : jsonUsers) {
                JSONObject jsonUserObj = (JSONObject) arrayItem;
                long id = (long) jsonUserObj.get("id");
                String username = jsonUserObj.get("username").toString();
                String firstname = jsonUserObj.get("firstname").toString();
                String lastname = jsonUserObj.get("lastname").toString();
                String fullname = jsonUserObj.get("fullname").toString();
                String email = jsonUserObj.get("email").toString();
                String department = jsonUserObj.get("department").toString();
                String idnumber = jsonUserObj.get("idnumber").toString();
                long firstaccess =(long) jsonUserObj.get("firstaccess");
                long lastaccess =(long) jsonUserObj.get("lastaccess");
                String description = jsonUserObj.get("description").toString();
                long descriptionformat =(long) jsonUserObj.get("descriptionformat");
                String city = jsonUserObj.get("city").toString();
                String country = jsonUserObj.get("country").toString();
                String profileimageurlsmall = jsonUserObj.get("profileimageurlsmall").toString();
                String profileimageurl = jsonUserObj.get("profileimageurl").toString();
                MoodleUser user = new MoodleUser(id, username, firstname, lastname, fullname, email, department, idnumber, firstaccess, lastaccess, description, descriptionformat, city, country, profileimageurlsmall, profileimageurl);
                users.add(user);
            }
        }

        return users;
}
    
       /**
     * Get all users (supplementary method).
     *
     * @return total set of MoodleUsers instances.
     * @throws MoodleException
     * @throws ParseException
     */
    public Set<MoodleUser> getAllUsers() throws MoodleException, ParseException {
        Map<String, String> criteria = new HashMap<String, String>();
        Set<MoodleUser> users = getUsers(criteria);
        return users;
    }
    
    
    /**
     * Get a single user by user id (supplementary method). 
     * @param userId  unique user Id.
     * @return MoodleCategory instance
     * @throws MoodleException
     * @throws ParseException
     */
    public MoodleUser getUserById(String userId) throws MoodleException, ParseException {
        Map<String, String> criteria = new HashMap<>();
        criteria.put("id", userId);
        Set<MoodleUser> users = getUsers(criteria);
        if (users.size() != 1) {
            new MoodleException("Duplcate", "duplicate id", "Duplicate id values!");
        }
        MoodleUser user = users.iterator().next();
        return user;
    }
    
    
    /**
     * Universal method for updating of users.
     *
     * @param updatedUsers set of users with updated properties
     * @throws MoodleException
     */
    public void updateUsers(Set<MoodleUser> updatedUsers) throws MoodleException {

        MoodleRestWSConfigSingleton config = MoodleRestWSConfigSingleton.getInstance();

        String domainName = config.getDomainName();
        String token = config.getToken();
        String restformat = config.getRestFormat();
        //Web-service's function name
        String functionName = "core_user_update_users";

        StringBuilder urlParameters = new StringBuilder();
        int i = 0;
        for (MoodleUser user : updatedUsers) {
            try {
                urlParameters.append("&users[").append(i).append("][id]=").append(user.getId())
                        .append("&users[").append(i).append("][username]=").append(URLEncoder.encode(user.getUsername(), "UTF-8"))
                        .append("&users[").append(i).append("][password]=").append(URLEncoder.encode(user.getPassword(), "UTF-8"))
                        .append("&users[").append(i).append("][firstname]=").append(URLEncoder.encode(user.getFirstname(), "UTF-8"))
                        .append("&users[").append(i).append("][lastname]=").append(URLEncoder.encode(user.getLastname(), "UTF-8"))
                        .append("&users[").append(i).append("][email]=").append(URLEncoder.encode(user.getEmail(), "UTF-8"))
                         .append("&users[").append(i).append("][auth]=").append(URLEncoder.encode(user.getAuth(), "UTF-8"))
                         .append("&users[").append(i).append("][idnumber]=").append(URLEncoder.encode(user.getIdnumber(), "UTF-8"))
                         .append("&users[").append(i).append("][lang]=").append(URLEncoder.encode(user.getLang(), "UTF-8"))
                         .append("&users[").append(i).append("][calendartype]=").append(URLEncoder.encode(user.getCalendartype(), "UTF-8"))
                         .append("&users[").append(i).append("][theme]=").append(URLEncoder.encode(user.getTheme(), "UTF-8"))
                         .append("&users[").append(i).append("][timezone]=").append(URLEncoder.encode(user.getTimezone(), "UTF-8"))
                        .append("&users[").append(i).append("][mailformat]=").append(user.getMailformat())
                        .append("&users[").append(i).append("][description]=").append(URLEncoder.encode(user.getDescription(), "UTF-8"))
                        .append("&users[").append(i).append("][city]=").append(URLEncoder.encode(user.getCity(), "UTF-8"))
                        .append("&users[").append(i).append("][country]=").append(URLEncoder.encode(user.getCountry(), "UTF-8"))
                        .append("&users[").append(i).append("][firstnamephonetic]=").append(URLEncoder.encode(user.getFirstnamephonetic(), "UTF-8"))
                        .append("&users[").append(i).append("][lastnamephonetic]=").append(URLEncoder.encode(user.getLastnamephonetic(), "UTF-8"))
                        .append("&users[").append(i).append("][middlename]=").append(URLEncoder.encode(user.getMidlename(), "UTF-8"))
                        .append("&users[").append(i).append("][alternatename]=").append(URLEncoder.encode(user.getAlternatename(), "UTF-8"));
                        } catch (UnsupportedEncodingException ex) {
                Logger.getLogger(MoodleCategoryWS.class
                        .getName()).log(Level.SEVERE, null, ex);
            }
            i++;
        }

        //Request to Web-service's function invoke - returns "null"
        String response = MoodleRestWSConnector.moodleWSRestCall(restformat, domainName, token, functionName, urlParameters.toString());
    }
   
    
}
